﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using COFE.Core.Filter;
using System.Text.RegularExpressions;
using COFE.Core.EntryType;

namespace COFE.Core.Utils
{

    public static class FilterUtils2
    {
        public static Tuple<Type, Func<string, string, IEntryFilter>> Tuple(Type type,
   Func<string, string, IEntryFilter> constructFunc)
        {
            return new Tuple<Type, Func<string, string, IEntryFilter>>(type, constructFunc);
        }

        public static Tuple<Type, Func<string, string, IOptionFilter>> Tuple(Type type,
   Func<string, string, IOptionFilter> constructFunc)
        {
            return new Tuple<Type, Func<string, string, IOptionFilter>>(type, constructFunc);
        }

        public static Tuple<Type, IEntryTypeIconProvider> Tuple(Type type,IEntryTypeIconProvider provider)
        {
            return new Tuple<Type, IEntryTypeIconProvider>(type, provider);
        }

        public static Guid GetId(this IEntryFilter[] entryFilters)
        {
            return FilterUtils2<IEntryFilter>.GetId(entryFilters);
        }

        public static Guid GetId(this IOptionFilter[] entryFilters)
        {
            return FilterUtils2<IOptionFilter>.GetId(entryFilters);
        }

        //public static bool FilterToKeyValuePair(string filterStr, out string key, out string value)
        //{
        //    key = null;
        //    value = null;

        //    Regex regexNextToken = new Regex(RegexPatterns.ParseParamStringPattern2);
        //    var match = regexNextToken.Match(filterStr);
        //    if (!match.Success)
        //        return false;
        //    key = match.Groups["key"].Value;
        //    value = match.Groups["value"].Value;
        //    return true;
        //}

        public static bool MatchPropertyFilters(object property, MatchMode matchMode, params IPropertyFilter[] filters)
        {
            if (filters.Length == 0)
                return true;
            else
            {
                switch (matchMode)
                {
                    case MatchMode.All:
                        foreach (var f in filters) if (!f.Match(property)) return false;
                        return true;
                    case MatchMode.Any:
                        foreach (var f in filters) if (f.Match(property)) return true;
                        return false;
                }
            }
            return false;
        }

        public static IEnumerable<T> UpdateOptionFilterExpressions<T>(IEnumerable<T> original, IOptionFilter[] optionFilters)
            where T : IFileSystemInfo
        {
            var paginateLookup = optionFilters.FirstOrDefault(lf => lf is PaginateOptionFilter) as PaginateOptionFilter;
            var sortResultLoookup = optionFilters.FirstOrDefault(lf => lf is SortResultOptionFilter) as SortResultOptionFilter;

            var expression = original;


            if (sortResultLoookup != null)
            {
                PropertyPairComparer comparer = new PropertyPairComparer(sortResultLoookup.SortProperty);

                if (sortResultLoookup.SortDirection == SortDirectionType.Ascending)
                    expression = expression.OrderBy(
                        e => e.InternalProperties.GetProperty(sortResultLoookup.SortProperty), comparer);
                else expression = expression.OrderByDescending(
                    e => e.InternalProperties.GetProperty(sortResultLoookup.SortProperty), comparer);
            }
            if (paginateLookup != null)
                expression = expression.Skip(paginateLookup.Skip)
                    .Take(paginateLookup.ItemsPerPage);
            return expression;                       
        }
    }

    public static class FilterUtils2<T> where T : IFilter
    {
        static FilterUtils2()
        {

        }

        static Dictionary<Type, IEntryTypeIconProvider> _iconProviderDic = new Dictionary<Type, IEntryTypeIconProvider>();
        public static void RegisterIconProvider(Type typeFilterType, IEntryTypeIconProvider provider)
        {
            if (typeof(T).IsAssignableFrom(typeFilterType))
            {
                lock (_iconProviderDic)
                    if (_iconProviderDic.ContainsKey(typeFilterType))
                        _iconProviderDic[typeFilterType] = provider;
                    else _iconProviderDic.Add(typeFilterType, provider);
            }
        }

        public static IEntryTypeIconProvider GetIconProvider(IEntryFilter typeFilter)
        {
            lock (_iconProviderDic)
                if (_iconProviderDic.ContainsKey(typeFilter.GetType()))
                    return _iconProviderDic[typeFilter.GetType()];
            return ResourceIconProvider.Instance;
        }        

        public static void RegisterFilter(Type filterType, Func<string, string, T> constructMethod)
        {
            if (filterType.GetInterface("IFilter") == null)
                throw new ArgumentException("FilterType is not an IFilter.");

            var fa = FilterAttribute.GetFilterAttribute(filterType);
            FactoryRegister<T>.RegisterFactory(fa.FilterName, constructMethod,
                (f) => f.GetSearchString());
        }

        public static void RegisterFilter(Type filterType)
        {
            RegisterFilter(filterType, (id, param) =>
                (T)Activator.CreateInstance(filterType, 
                new object[] { param, id })
                );
        }

        public static bool FilterExists(string filter)
        {
            return FactoryRegister<T>.FindFactory(filter) != null;
        }

        
        public static string FilterToString(T filter)
        {
            return COFEShared.FilterParser.FilterToFilterString(filter);
        }

        public static Guid GetId(T[] filters)
        {
            return StringUtils<IEntryFilter>.GetDeterministicGuid(
                COFEShared.FilterParser.FilterToFilterString(
                filters as IFilter[]));
        }

        public static T StringToFilter(string input)
        {
            var param1 = COFEShared.FilterParser.Serializer.StringToProperty(input).First();
            return StringToFilter(param1.Item1, param1.Item2);
        }

        public static T StringToFilter(string key, string value)
        {                   
            var lookupKey = key.TrimStart('-');
            var factory = FactoryRegister<T>.FindFactory(lookupKey);
            if (factory == null)
                throw new KeyNotFoundException(key);
            return factory.Construct(key, value);
        }

        //public static T StringToFilter(string input)
        //{
        //    string key, value;
        //    FilterUtils2.FilterToKeyValuePair(input, out key, out value);
        //    var factory = FactoryRegister<T>.FindFactory(key);
        //    if (factory == null)
        //        throw new KeyNotFoundException(key);
        //    return factory.Construct(null, value);
        //}

       
        //public static T[] StringArrayToFilterArray(string[] strArray)
        //{
        //    return (from s in strArray select StringToFilter(s)).ToArray();
        //}

        //public static T[] ParamStringToFilterArray(string input)
        //{
        //    var dic = StringUtils.ParamStringToDic(input, RegexPatterns.ParseParamStringPattern2);
        //    return (from ppair in dic
        //            where FilterExists(ppair.Item1)
        //            select StringToFilter(String.Format("{0}=({1})", ppair.Item1, ppair.Item2))).ToArray();
        //}


    }
}
